package com.szxy.threaddemo.volidatetest;

import org.junit.jupiter.api.Test;

import java.time.Instant;
import java.util.ResourceBundle;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: zwz
 * @Date:2020/10/23 11:03
 * @Description: volatile 关键字测试
 **/
public class VolatileDemo {

    /**
     * 测试  volatile 保证可见性
     */
    @Test
    public void test01() {
        DataDemo data = new DataDemo();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " coming...");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 调用
            data.addOne();
            System.out.println("exec addOne ： data.a = " + data.a);
            System.out.println(Thread.currentThread().getName() + " updated...");
        }).start();

        while (data.a == 0) {
            // loop
        }

        System.out.println("exec over: data.a = " + data.a);
        System.out.println(Thread.currentThread().getName() + " over...");
    }


    /**
     * 测试 volatile 不保证原子性
     */
    @Test
    public void test02() {
        DataDemo data = new DataDemo();
        // 创建 20 个线程， 累加 data.a l
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    data.addOne();
                }
            }).start();
        }

        // 默认有 main 线程和 gc 线程
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }

        System.out.println("data.a = " + data.a);
    }


    /**
     * 测试 volatile 禁止指令重排
     */
    @Test
    public void test03() {
        CountDownLatch countDownLatch = new CountDownLatch(2);
        ReSortSeqDemo demo = new ReSortSeqDemo();
        Worker1 worker1 = new Worker1(countDownLatch, demo);
        Worker2 worker2 = new Worker2(countDownLatch, demo);
        new Thread(worker1).start();
        countDownLatch.countDown();
        new Thread(worker2).start();
        countDownLatch.countDown();
    }


    /**
     * 你那些地方用到 volatile 关键字
     */
    @Test
    public void test04() throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            Future<SingleDemo> result = executor.submit(() -> SingleDemo.getInstance());
            System.out.println(result.get());
        }
        executor.shutdown();
    }
}

class DataDemo {
    //    int a = 0;
    volatile int a = 0;
    // private ReentrantLock lock = new ReentrantLock();

    public void addOne() {
        this.a += 1;
    }
}

/**
 * 工作线程
 */
class Worker implements Runnable {
    private CountDownLatch countDownLatch;

    Worker(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            this.countDownLatch.await();
            System.out.println(Thread.currentThread().getName() + "@" + Instant.now().toEpochMilli());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Worker1 implements Runnable {
    private CountDownLatch countDownLatch;
    private ReSortSeqDemo reSortSeqDemo;

    Worker1(CountDownLatch countDownLatch, ReSortSeqDemo reSortSeqDemo) {
        this.countDownLatch = countDownLatch;
        this.reSortSeqDemo = reSortSeqDemo;
    }

    @Override
    public void run() {
        try {
            this.countDownLatch.await();
            System.out.println(Thread.currentThread().getName() + "@" + Instant.now().toEpochMilli());
            this.reSortSeqDemo.method01();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Worker2 implements Runnable {
    private CountDownLatch countDownLatch;
    private ReSortSeqDemo reSortSeqDemo;

    Worker2(CountDownLatch countDownLatch, ReSortSeqDemo reSortSeqDemo) {
        this.countDownLatch = countDownLatch;
        this.reSortSeqDemo = reSortSeqDemo;
    }

    @Override
    public void run() {
        try {
            this.countDownLatch.await();
            System.out.println(Thread.currentThread().getName() + "@" + Instant.now().toEpochMilli());
            this.reSortSeqDemo.method02();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ReSortSeqDemo {
    int a = 0;
    boolean flag = false;

    public void method01() {
        a = 1;           // flag = true;
        // ----线程切换----
        flag = true;     // a = 1;
    }

    public void method02() {
        if (flag) {
            a = a + 3;
            System.out.println("a = " + a);
        }
    }
}

/**
 * 单例模式
 */
class SingleDemo {
    // 防止指令重排
    private static volatile SingleDemo singleDemo = null;

    SingleDemo() {
        System.out.println(Thread.currentThread().getName() + " constructor init ...");
    }

    /**
     * 双重检查锁
     *
     * @return
     */
    public static SingleDemo getInstance() {
        if (singleDemo == null) {
            synchronized (SingleDemo.class) {
                if (singleDemo == null) {
                    singleDemo = new SingleDemo();
                }
            }
        }
        return singleDemo;
    }
}

